package com.haredot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haredot.constraint.RedisConst;
import com.haredot.entity.Message;
import com.haredot.entity.UserBlack;
import com.haredot.holder.TokenContextHolder;
import com.haredot.mapper.MessageMapper;
import com.haredot.mapper.UserBlackMapper;
import com.haredot.service.MessageService;
import com.haredot.vo.MessageVo;
import com.haredot.vo.R;
import com.haredot.vo.UserBlackVo;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【tb_message】的数据库操作Service实现
 * @createDate 2023-09-12 21:52:33
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService {

    @Resource
    private RedisTemplate<String, Message> redisTemplate;

    @Resource
    private UserBlackMapper userBlackMapper;

    @Override
    public R<Message> queryMessageRecords(Long offset, Long unread, Long toUserId) {
        // 获取当前登录的用户ID
        Long fromUserId = TokenContextHolder.getCurrentUserId();

        final String redisKey = MessageFormat.format(RedisConst.CHAT_MESSAGE_TEMPLATE, String.valueOf(toUserId), String.valueOf(fromUserId));
        // 查询 2 个人 之间最新的聊天的记录。
        //List<MessageVo> messagePage =  this.getBaseMapper().findMessageRecordsBetweenTwoUser(offset, rows , fromUserId, toUserId);
        // 从 redis 中查询数据、如果 offset = 0 , 则查询所有的未读消息
        if (offset == 0 && unread > 0) {
            // redis 中 的 start , end 均包含 ， 所以 rows 要减去 1
            Set<Message> messages = redisTemplate.opsForZSet().reverseRange(redisKey, 0, unread - 1);
            // 移除对应的 messages
            if (!messages.isEmpty()) {
                redisTemplate.opsForZSet().remove(redisKey, messages.toArray());
                // 修改他们的状态为已读
                Set<ZSetOperations.TypedTuple<Message>> collect = messages.stream().map(message -> {
                    message.setNread(true);
                    long epoch = message.getCreateTime().toInstant(ZoneOffset.UTC).toEpochMilli();
                    return new DefaultTypedTuple<>(message, Double.valueOf(epoch));
                }).collect(Collectors.toSet());
                // 将对应的 消息存储 Set集合
                redisTemplate.opsForZSet().add(redisKey, collect);
                // 更新一下数据库
                this.getBaseMapper().batchUpdateMessageReadStateTrue(messages);
            }
            // 返回结果
            return R.<Message>ok().data(new ArrayList<>(messages));
        }
        // 如果 rows = 0 （没有未读的聊天记录、则查询从偏移量开始的5条数据）
        if (unread == 0) {
            final String myRedisKey = MessageFormat.format(RedisConst.CHAT_MESSAGE_TEMPLATE, String.valueOf(fromUserId), String.valueOf(toUserId));

            String tempKey = "chat:all::" + fromUserId + ":" + fromUserId;
            // 合并两个人的聊天信息
            redisTemplate.opsForZSet().unionAndStore(redisKey, myRedisKey, tempKey);
            Set<Message> messages = redisTemplate.opsForZSet().reverseRange(tempKey, offset, offset + 4);
            redisTemplate.delete(tempKey);
            return R.<Message>ok().data(new ArrayList<>(messages));
        }

        return R.<Message>fail("数据格式错误").build();
    }

    @Override
    public R<?> updateMessage(Long messageId) {
        Long currentUserId = TokenContextHolder.getCurrentUserId();
        // 查询 消息
        MessageVo message = this.getBaseMapper().findMessage(messageId);
        // 从 redis 中找到 别人发给我的消息
        final String redisKey = MessageFormat.format(RedisConst.CHAT_MESSAGE_TEMPLATE, String.valueOf(message.getFromUser()),
                String.valueOf(currentUserId));

        // 从 Redis 中删除 查找到的消息
        redisTemplate.opsForZSet().remove(redisKey, message);

        // 将 message 设置为 已读
        message.setNread(true);
        // 写入到 redis 中
        redisTemplate.opsForZSet().add(redisKey, message, message.getCreateTime().toInstant(ZoneOffset.UTC).toEpochMilli());
        this.update(new LambdaUpdateWrapper<Message>().set(Message::isNread, true).eq(Message::getId, messageId));

        return R.ok().build();
    }

    @Override
    public R<?> queryBlackList(Page<UserBlackVo> page) {
        // 获取当前登录的用户ID
        Long currentUserId = TokenContextHolder.getCurrentUserId();

        // 查询黑名单用户信息
        Page<UserBlackVo> ret = this.userBlackMapper.findUserBlackList(page, currentUserId);

        return R.<Page<UserBlackVo>>ok().data(ret);
    }

    @Override
    public R<?> bindBlackUser(Long blackUser) {
        // 获取当前登录的用户
        Long userId = TokenContextHolder.getCurrentUserId();
        // 判断当前用户是否已经在黑名单中
        UserBlack userBlack = this.userBlackMapper.selectOne(new LambdaQueryWrapper<UserBlack>()
                .eq(UserBlack::getUserId, userId).eq(UserBlack::getBlackUser, blackUser));

        if (userBlack != null) {
            return R.fail("该用户已经在黑名单中、请勿重复操作").build();
        }
        // 绑定黑名单
        this.userBlackMapper.insert(UserBlack.builder().blackUser(blackUser).userId(userId).build());
        return R.ok().build();
    }

    @Override
    public R<?> removeBlackUser(Long id) {
        int len = this.userBlackMapper.deleteById(id);
        return len == 1 ? R.ok().build() : R.fail().build();
    }
}




